<?php
	/**
	 * Web Service functionality class
	 * 
	 * @version 3.0
	 * @package Components
	 * @author Anton.Perkin
	 * 
	 */
	class WebService
	{
		
		/* CONSTRUCTORS */

		/**
		 * Default constructor
		 */
		function __construct()
		{
			require_once('nusoap.php');
		}
		
		
		/* PROPERTIES */
		
		/**
		 * XML string
		 *
		 * @var string
		 */
		private $xml;
		
		
		/* SOAP METHODS */
		
		/**
	     * Gets response from the web service through SOAP call
	     * 
	     * @param string $wsdlAddress WSDL file address to get web service response from
	     * @param string $functionName Web service function name
	     * @param array $parameters Function arguments
	     * @param array $options Array with predetermined parameters (i.e. array("login" => "test", "password" => "test"))
	     * 
	     * @return array Web service response
	     */
		public static function RequestResponse($wsdlAddress, $functionName, $parameters = array(), $options = array())
		{
			//parameters preparation
			$parameters = $this->SanitizeParameters($parameters);
			
			//client initialization
			$client = new soapclnt($wsdlAddress, $options);
			
			//response
			try
			{	
				$response =  $client->__soapCall($functionName, array('parameters' => $parameters));	  	
			}
			catch (SoapFault $exception) 
			{
				echo $exception;
			} 
			
			return $response;
		}	

		
		/* SOAP METHODS */
		
		/**
	     * Gets response from a web-service through NuSOAP call
	     * 
	     * @param string $wsdlAddress WSDL file address to get web service response from
	     * @param string $functionName Web service function name
	     * @param array $parameters Function arguments
	     * @param array $options Array with predetermined parameters (i.e. array("login" => "test", "password" => "test"))
	     * 
	     * @return array Web service response
	    */
		public function Call($wsdlAddress, $functionName, $parameters = array(), $options = array(), $headers = false)
		{
			//parameters preparation
			$parameters = $this->SanitizeParameters($parameters);
			
			//client initialization
			$client = new soapclnt($wsdlAddress, true);

			//sets credintials
			$options['username'] = isset($options['username']) ? $options['username'] : null;
			$options['password'] = isset($options['password']) ? $options['password'] : null;
			$client->setCredentials($options['username'], $options['password']);
			
			//default settings
			$client->soap_defencoding = (isset($options['soap_defencoding'])) ? $options['soap_defencoding'] : 'UTF-8';
			$client->decode_utf8 = (isset($options['decode_utf8'])) ? $options['decode_utf8'] : false;

			//response
			$response = $client->call($functionName, $parameters, 'http://tempuri.org', '', $headers);
			
			return $response;
		}
		
		/**
		 * Gets response from a web-service through XML NuSOAP call
		 * 
	     * @param string $wsdlAddress WSDL file address to get web service response from
	     * @param string $functionName Web service function name
		 * @param $parameters function parameters in associative array or objects array. E.g. array('Users' => array('Login'=>'test', 'Password=>'test')) in case of object(s) or array('Users' => array('Login'=>'test', 'Password=>'test')) in case of variables.
		 * @param array $options Array with predetermined parameters (i.e. array("login" => "test", "password" => "test"))
		 * 
		 * @return array Web service response
		 */
		public function XMLCall($wsdlAddress, $functionName, $parameters = array(), $options = array(), $headers = false, $namespaces = array())
		{
			//parameters preparation
			$parameters = $this->SanitizeParameters($parameters);
			
			//creates the client
			$client = new nusoap_client($wsdlAddress, true);
			
			//sets credintials
			$options['username'] = isset($options['username']) ? $options['username'] : null;
			$options['password'] = isset($options['password']) ? $options['password'] : null;
			$client->setCredentials($options['username'], $options['password']);
			
			//gets the proxy class
			$proxy = $client->getProxy();

			//soap action
			$soapAction = $proxy->operations[$functionName]['soapAction'];
			
			//namespace
			$namespace = $proxy->wsdl->namespaces['tns'];
			
			//gets XML from parameters array
			$XML = '';
			$XML .= (!isset($headers['SOAPAction'])) ? "<$functionName xmlns='$namespace'>" : '';
			$this->xml = '';

			foreach ($parameters as $name => $params)
			{
				if ($options['XML_object_by_attributes'] == true)
				{
					$this->GenerateXMLItemAttributes($name, $params);
				}
				else 
				{
					$this->GenerateXMLItem($name, $params);
				}
			}
			$XML .= $this->xml;
			$XML .= (!isset($headers['SOAPAction'])) ? "</$functionName>" : '';
			
			$XML = eregi_replace("_[0-9]+", '', $XML);
			
			//calls the service and gets response
			$msg = $client->serializeEnvelope($XML, $headers, $namespaces);
			
//			Debugger::VarDump($msg);
			
			$response = $client->send($msg, $soapAction);
			
			return $response;			
		}
		
		
		/* PRIVATE METHODS */
		
		/**
		 * Prepares the parameters
		 *
		 * @param mixed $parameters parameters
		 */
		private function SanitizeParameters($parameters = array())
		{
			return (empty($parameters)) ? array() : (array)$parameters;
		}
		
		/**
		 * Generates XML item
		 *
		 * @param item name $name
		 * @param item $item
		 */
		private function GenerateXMLItem($name, $item)
		{
			if (is_array($item))
			{
				$this->xml .= "<$name>";
				foreach ($item as $key => $value)
				{
					$this->GenerateXMLItem($key, $value);
				}
				$this->xml .= "</$name>";
			}
			else 
			{
				$this->xml .= "<$name>$item</$name>";
			}
			
			return;
		}
		
		/**
		 * Generates XML item with attributes as childs
		 *
		 * @param item name $name
		 * @param item $item
		 */
		private function GenerateXMLItemAttributes($name, $item)
		{
			$depth = $this->calculateAttayDepth($item);
			if ($depth < 2)
			{
				$this->xml .= "<$name";
				foreach ($item as $key => $value)
				{
					$this->xml .= ' '.$key.' = "'.$value.'" ';
				}
				$this->xml .= " />";
			}
			else 
			{
				if (!isset($item['attributes']))
				{
					$this->xml .= "<$name>";
				}
				else 
				{
					$this->xml .= "<$name";
					foreach ($item['attributes'] as $attrKey => $attrValue)
					{
						$this->xml .= ' '.$attrKey.' = "'.$attrValue.'" ';
					}
					$this->xml .= " >";
					unset($item['attributes']);
				}
				
				foreach ($item as $k => $v)
				{
					$this->GenerateXMLItemAttributes($k, $v);
				}
				$this->xml .= "</$name>";
			}
			
			return;
		}		
		
		/**
		 * Calculates array depth
		 *
		 * @param array $array
		 * @return number array depth
		 */
		private function calculateAttayDepth($array) 
		{
		    $max_depth = 1;
		
		    foreach ($array as $val) {
		        if (is_array($val)) {
		            $depth = $this->calculateAttayDepth($val) + 1;
		
		            if ($depth > $max_depth) {
		                $max_depth = $depth;
		            }
		        }
		    }
		
		    return $max_depth;
		}
		
	}
?>